package com.yqg.protection.netty.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yqg.protection.entity.*;
import com.yqg.protection.service.*;
import com.yqg.protection.utils.ByteUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * projectName:xf-service
 * author:zxf
 * time:2025/8/1 17:39
 * description:
 */
@Component
@Slf4j
public class Sdf300Service extends ProtocolService {

    @Autowired
    private IWarnRecordService warnRecordService;
    @Autowired
    private IEquipmentInputStoreService equipmentInputStoreService;
    @Autowired
    private IFireSysDataService fireSysDataService;
    @Autowired
    IFireSysStateDataService fireSysStateDataService;
    @Autowired
    ITemporaryDataService temporaryDataService;
    @Autowired
    ISdf300CurrentDataService sdf300CurrentDataService;
    @Autowired
    ISdf300HistoryDataService sdf300HistoryDataService;
    @Autowired
    ISdf300WarnDataService sdf300WarnDataService;

    /**
     * 解析SDF300设备数据
     *
     * @param value    原始数据字符串
     * @param deviceId 设备ID
     * @param sendTime 发送时间
     */
    public void analyzeSdf300Data(String value, String deviceId, String sendTime) {
        try {
            log.info("===== 开始解析SDF300设备数据[设备ID:{}] =====", deviceId);
            log.info("原始数据VALUE部分: {}", value);

            // 1. 解析设备类型和子型号
            String deviceType = value.substring(0, 2);
            log.info("设备类型(DIO): {} (SDF300设备应为03)", deviceType);

            String subType = value.substring(2, 4);
            log.info("设备子型号(DII): {}", subType);

            // 解析子型号的各个位
            byte[] subTypeArray = ByteUtil.getBooleanArray(ByteUtil.hexStringToByteArray(subType));
            log.info("子型号解析: ");
            log.info("  位0(电能标志): {} -> {}", subTypeArray[7], subTypeArray[7] == 1 ? "有电能" : "无电能");
            log.info("  位1(谐波标志): {} -> {}", subTypeArray[6], subTypeArray[6] == 1 ? "有谐波" : "无谐波");
            log.info("  位4(相数标志): {} -> {}", subTypeArray[3], subTypeArray[3] == 1 ? "三相" : "单相");
            log.info("  位5(DI通道): {} -> {}", subTypeArray[2], subTypeArray[2] == 1 ? "4DI" : "2DI");

            // 2. 解析通道配置
            String leakageChannels = value.substring(4, 6);
            log.info("漏电通道数: {}", Integer.parseInt(leakageChannels, 16));

            String tempChannels = value.substring(6, 8);
            log.info("温度通道数: {}", Integer.parseInt(tempChannels, 16));

            // 3. 解析状态位
            String alarmBits = value.substring(8, 12);  // 报警状态 (2字节)
            log.info("报警状态位(AlarmBits): {} -> 二进制: {}",
                    alarmBits,
                    String.format("%16s", Integer.toBinaryString(Integer.parseInt(alarmBits, 16))).replace(' ', '0'));
            byte[] alarmBitsArray = ByteUtil.getBooleanArray(ByteUtil.hexStringToByteArray(alarmBits));
            log.info("  位0(漏电): {} -> {}", alarmBitsArray[15], alarmBitsArray[15] == 1 ? "报警" : "正常");
            log.info("  位1(温度1): {} -> {}", alarmBitsArray[14], alarmBitsArray[14] == 1 ? "报警" : "正常");
            log.info("  位2(温度2): {} -> {}", alarmBitsArray[13], alarmBitsArray[13] == 1 ? "报警" : "正常");
            log.info("  位3(温度3): {} -> {}", alarmBitsArray[12], alarmBitsArray[12] == 1 ? "报警" : "正常");
            log.info("  位4(温度4): {} -> {}", alarmBitsArray[11], alarmBitsArray[11] == 1 ? "报警" : "正常");
            log.info("  位8(DI1联动): {} -> {}", alarmBitsArray[7], alarmBitsArray[7] == 1 ? "报警" : "正常");
            log.info("  位9(DI2联动): {} -> {}", alarmBitsArray[6], alarmBitsArray[6] == 1 ? "报警" : "正常");

            String faultBits = value.substring(12, 16); // 故障状态 (2字节)
            log.info("故障状态位(FaultBits): {} -> 二进制: {}",
                    faultBits,
                    String.format("%16s", Integer.toBinaryString(Integer.parseInt(faultBits, 16))).replace(' ', '0'));
            byte[] faultBitsArray = ByteUtil.getBooleanArray(ByteUtil.hexStringToByteArray(faultBits));
            log.info("  位0(漏电): {} -> {}", faultBitsArray[15], faultBitsArray[15] == 1 ? "故障，相应通道的实时值无效" : "正常");
            log.info("  位1(温度1): {} -> {}", faultBitsArray[14], faultBitsArray[14] == 1 ? "故障，相应通道的实时值无效" : "正常");
            log.info("  位2(温度2): {} -> {}", faultBitsArray[13], faultBitsArray[13] == 1 ? "故障，相应通道的实时值无效" : "正常");
            log.info("  位3(温度3): {} -> {}", faultBitsArray[12], faultBitsArray[12] == 1 ? "故障，相应通道的实时值无效" : "正常");
            log.info("  位4(温度4): {} -> {}", faultBitsArray[11], faultBitsArray[11] == 1 ? "故障，相应通道的实时值无效" : "正常");

            String linkBits = value.substring(16, 20);  // 使能状态 (2字节)
            log.info("使能状态位(LinkBits): {} -> 二进制: {}",
                    linkBits,
                    String.format("%16s", Integer.toBinaryString(Integer.parseInt(linkBits, 16))).replace(' ', '0'));
            byte[] linkBitsArray = ByteUtil.getBooleanArray(ByteUtil.hexStringToByteArray(linkBits));
            log.info("  位0(漏电): {} -> {}", linkBitsArray[15], linkBitsArray[15] == 1 ? "通道开启" : "通道关闭,相应通道报警、故障、实时值等参数全部无效");
            log.info("  位1(温度1): {} -> {}", linkBitsArray[14], linkBitsArray[14] == 1 ? "通道开启" : "通道关闭,相应通道报警、故障、实时值等参数全部无效");
            log.info("  位2(温度2): {} -> {}", linkBitsArray[13], linkBitsArray[13] == 1 ? "通道开启" : "通道关闭,相应通道报警、故障、实时值等参数全部无效");
            log.info("  位3(温度3): {} -> {}", linkBitsArray[12], linkBitsArray[12] == 1 ? "通道开启" : "通道关闭,相应通道报警、故障、实时值等参数全部无效");
            log.info("  位4(温度4): {} -> {}", linkBitsArray[11], linkBitsArray[11] == 1 ? "通道开启" : "通道关闭,相应通道报警、故障、实时值等参数全部无效");
            log.info("  位8(DI1): {} -> {}", linkBitsArray[7], linkBitsArray[7] == 1 ? "闭合" : "断开");
            log.info("  位9(DI2): {} -> {}", linkBitsArray[6], linkBitsArray[6] == 1 ? "闭合" : "断开");
            log.info("  位10(DO1): {} -> {}", linkBitsArray[7], linkBitsArray[7] == 1 ? "闭合" : "断开");
            log.info("  位11(DO2联动): {} -> {}", linkBitsArray[6], linkBitsArray[6] == 1 ? "闭合" : "断开");

            String limitBits = value.substring(20, 24); // 电量告警状态 (2字节)
            log.info("电力报警状态位(LimitBits): {} -> 二进制: {}",
                    limitBits,
                    String.format("%16s", Integer.toBinaryString(Integer.parseInt(limitBits, 16))).replace(' ', '0'));
            byte[] limitBitsArray = ByteUtil.getBooleanArray(ByteUtil.hexStringToByteArray(limitBits));
            log.info("  位0(过压): {} -> {}", limitBitsArray[15], limitBitsArray[15] == 1 ? "报警" : "正常");
            log.info("  位1(欠压): {} -> {}", limitBitsArray[14], limitBitsArray[14] == 1 ? "报警" : "正常");
            log.info("  位2(缺相): {} -> {}", limitBitsArray[13], limitBitsArray[13] == 1 ? "报警" : "正常");
            log.info("  位3(过流): {} -> {}", limitBitsArray[12], limitBitsArray[12] == 1 ? "报警" : "正常");
            log.info("  位4(过载): {} -> {}", limitBitsArray[11], limitBitsArray[11] == 1 ? "报警" : "正常");

            // 4. 解析测量值
            String leakageValue = value.substring(24, 28); // 漏电值 (2字节)
            float actualLeakage = Integer.parseInt(leakageValue, 16) * 1.0f; // mA
            log.info("漏电值: {} (原始: {}) -> {} mA", leakageValue, leakageValue, actualLeakage);

            // 5. 解析4路温度值
            float[] actualTemps = new float[4];
            actualTemps[0] = Integer.parseInt(value.substring(28, 32), 16) * 1.0f;
            actualTemps[1] = Integer.parseInt(value.substring(32, 36), 16) * 1.0f;
            actualTemps[2] = Integer.parseInt(value.substring(36, 40), 16) * 1.0f;
            actualTemps[3] = Integer.parseInt(value.substring(40, 44), 16) * 1.0f;
            log.info("温度值: ");
            log.info("  通道1: {} (原始: {}) -> {} ℃", value.substring(28, 32), value.substring(28, 32), actualTemps[0]);
            log.info("  通道2: {} (原始: {}) -> {} ℃", value.substring(32, 36), value.substring(32, 36), actualTemps[1]);
            log.info("  通道3: {} (原始: {}) -> {} ℃", value.substring(36, 40), value.substring(36, 40), actualTemps[2]);
            log.info("  通道4: {} (原始: {}) -> {} ℃", value.substring(40, 44), value.substring(40, 44), actualTemps[3]);

            // 6. 解析变比参数
            String ptRatio = value.substring(44, 52); // 电压变比 (4字节)
            int actualPtRatio = Integer.parseInt(ptRatio, 16);
            log.info("电压变比(PT): {} (原始: {}) -> {}", ptRatio, ptRatio, actualPtRatio);

            String ctRatio = value.substring(52, 60); // 电流变比 (4字节)
            int actualCtRatio = Integer.parseInt(ctRatio, 16);
            log.info("电流变比(CT): {} (原始: {}) -> {}", ctRatio, ctRatio, actualCtRatio);

            // 7. 解析电压电流值
            String voltage1 = value.substring(60, 64); // 电压A (2字节)
            float twiceActualVoltage1 = Integer.parseInt(voltage1, 16) * 0.1f; // V
            float actualVoltage1 = twiceActualVoltage1 * actualPtRatio;
            log.info("电压A: {} (电网二次值: {}) -> 电网的一次值{} V", voltage1, twiceActualVoltage1, actualVoltage1);
            String voltage2 = value.substring(64, 68); // 电压B (2字节)
            float twiceActualVoltage2 = Integer.parseInt(voltage2, 16) * 0.1f; // V
            float actualVoltage2 = twiceActualVoltage1 * actualPtRatio;
            log.info("电压B: {} (电网二次值: {}) -> 电网的一次值{} V", voltage2, twiceActualVoltage2, actualVoltage2);
            String voltage3 = value.substring(68, 72); // 电压C (2字节)
            float twiceActualVoltage3 = Integer.parseInt(voltage3, 16) * 0.1f; // V
            float actualVoltage3 = twiceActualVoltage3 * actualPtRatio;
            log.info("电压C: {} (电网二次值: {}) -> 电网的一次值{} V", voltage3, twiceActualVoltage3, actualVoltage3);

            String current1 = value.substring(72, 76); // 电流A (2字节)
            float twiceActualCurrent1 = Integer.parseInt(current1, 16) * 0.001f; // A
            float actualCurrent1 = twiceActualCurrent1 * actualCtRatio;
            log.info("电流A: {} (电网二次值: {}) -> 电网的一次值{} A", current1, twiceActualCurrent1, actualCurrent1);
            String current2 = value.substring(76, 80); // 电流B (2字节)
            float twiceActualCurrent2 = Integer.parseInt(current2, 16) * 0.001f; // A
            float actualCurrent2 = twiceActualCurrent2 * actualCtRatio;
            log.info("电流B: {} (电网二次值: {}) -> 电网的一次值{} A", current2, twiceActualCurrent2, actualCurrent2);
            String current3 = value.substring(80, 84); // 电流C (2字节)
            float twiceActualCurrent3 = Integer.parseInt(current3, 16) * 0.001f; // A
            float actualCurrent3 = twiceActualCurrent3 * actualCtRatio;
            log.info("电流C: {} (电网二次值: {}) -> 电网的一次值{} A", current3, twiceActualCurrent3, actualCurrent3);

            // 8. 解析功率参数
            String power = value.substring(84, 88); // 功率 (2字节)
            float twiceActualPower = Integer.parseInt(power, 16) * 0.001f; // kW
            float actualPower = twiceActualPower * actualPtRatio * actualCtRatio;
            log.info("有功功率: {} (电网二次值: {}) -> 电网的一次值{} kW", power, twiceActualPower, actualPower);

            String energy = value.substring(88, 96); // 电能 (4字节)
            long twiceActualEnergy = Long.parseLong(energy, 16) * 1L; // kWh
            long actualEnergy = twiceActualEnergy * actualPtRatio * actualCtRatio;
            log.info("电能值: {} (电网二次值: {}) -> 电网的一次值{} kWh", energy, twiceActualEnergy, actualEnergy);

            // 9. 解析控制码
            String ctrlHex = value.substring(2, 4); // 控制码在VALUE的第2-3字节
            byte ctrlByte = Byte.parseByte(ctrlHex, 16);
            log.info("控制码(CTR): {} -> 二进制: {}",
                    ctrlHex,
                    String.format("%8s", Integer.toBinaryString(ctrlByte & 0xFF)).replace(' ', '0'));

            // 解析控制码的各个位
            int bit7_6 = (ctrlByte & 0xC0) >> 6; // 数据域/设置域/控制域
            int bit5 = (ctrlByte & 0x20) >> 5;    // 应答标识
            int bit4 = (ctrlByte & 0x10) >> 4;    // 通信状态
            int bit3_2 = (ctrlByte & 0x0C) >> 2;  // 上报模式
            int bit1_0 = ctrlByte & 0x03;         // 寻址模式

            log.info("控制码解析:");
            log.info("  bit7-6: {} -> {}", bit7_6,
                    bit7_6 == 0 ? "数据域" :
                            bit7_6 == 1 ? "设置域" :
                                    bit7_6 == 2 ? "控制域" : "保留");

            log.info("  bit5: {} -> {}", bit5, bit5 == 0 ? "无需应答" : "需应答");
            log.info("  bit4: {} -> {}", bit4, bit4 == 0 ? "通信异常" : "通信正常");

            log.info("  bit3-2: {} -> {}", bit3_2,
                    bit3_2 == 0 ? "主机轮询" :
                            bit3_2 == 1 ? "从机应答" :
                                    bit3_2 == 2 ? "定时上报" : "变位上报");

            log.info("  bit1-0: {} -> {}", bit1_0,
                    bit1_0 == 0 ? "四级地址寻址" :
                            bit1_0 == 1 ? "设备ID寻址" :
                                    bit1_0 == 2 ? "逻辑地址寻址" : "广播");

            // 10. 存储解析后的数据
            saveSdf300DataToDatabase(deviceId, sendTime, subTypeArray,
                    leakageChannels, tempChannels,
                    actualLeakage, actualTemps,
                    alarmBitsArray, faultBitsArray, linkBitsArray, limitBitsArray,
                    actualPtRatio, actualCtRatio,
                    actualVoltage1, actualVoltage2, actualVoltage3,
                    actualCurrent1, actualCurrent2, actualCurrent3,
                    actualPower, actualEnergy,
                    bit7_6, bit5, bit4, bit3_2, bit1_0);

            log.info("SDF300数据解析完成: 设备ID={}, 漏电值={}mA, 温度值={}℃",
                    deviceId, actualLeakage, Arrays.toString(actualTemps));

        } catch (Exception e) {
            log.error("解析SDF300数据时出错: {}", e.getMessage(), e);
        }
    }

    /**
     * 将SDF300数据保存到数据库
     */
    private void saveSdf300DataToDatabase(String deviceId, String sendTime, byte[] subTypeArray, String leakageChannels, String tempChannels, float actualLeakage, float[] actualTemps, byte[] alarmBitsArray, byte[] faultBitsArray, byte[] linkBitsArray, byte[] limitBitsArray, int actualPtRatio, int actualCtRatio, float actualVoltage1, float actualVoltage2, float actualVoltage3, float actualCurrent1, float actualCurrent2, float actualCurrent3, float actualPower, long actualEnergy, int bit7_6, int bit5, int bit4, int bit3_2, int bit1_0) {
        //更新设备状态
        EquipmentInputStore equipmentInputStore = getEquipmentInputStore(deviceId);
        if ((linkBitsArray[15] == 1 && faultBitsArray[15] == 1) || (linkBitsArray[14] == 1 && faultBitsArray[14] == 1) || (linkBitsArray[13] == 1 && faultBitsArray[13] == 1) || (linkBitsArray[12] == 1 && faultBitsArray[12] == 1) || (linkBitsArray[11] == 1 && faultBitsArray[11] == 1)) {
            equipmentInputStore.setState("2");
        } else if ((linkBitsArray[15] == 1 && alarmBitsArray[15] == 1) || (linkBitsArray[14] == 1 && alarmBitsArray[14] == 1) || (linkBitsArray[13] == 1 && alarmBitsArray[13] == 1) || (linkBitsArray[12] == 1 && alarmBitsArray[12] == 1) || (linkBitsArray[11] == 1 && alarmBitsArray[11] == 1) || alarmBitsArray[7] == 1 || alarmBitsArray[6] == 1) {
            equipmentInputStore.setState("1");
        } else {
            equipmentInputStore.setState("0");
        }
        equipmentInputStore.setUpdateTime(sendTime);
        equipmentInputStoreService.saveOrUpdate(equipmentInputStore);

        // 记录设备全部数据 - 实时与历史
        Long equipmentInputStoreId = equipmentInputStore.getId();
        LocalDateTime sendTimeDT = LocalDateTime.parse(sendTime.replace(" ", "T"));

        // 构建实时数据对象
        Sdf300CurrentData currentData = new Sdf300CurrentData();
        currentData.setEquipmentInputStoreId(equipmentInputStoreId);
        currentData.setSendTime(sendTimeDT);
        currentData.setHasPower((int) subTypeArray[7]);
        currentData.setHasHarmonic((int) subTypeArray[6]);
        currentData.setPhaseType((int) subTypeArray[3]);
        currentData.setDiChannels((int) subTypeArray[2]);
        currentData.setLeakageAlarmBit((int) alarmBitsArray[15]);
        currentData.setTemp1AlarmBit((int) alarmBitsArray[14]);
        currentData.setTemp2AlarmBit((int) alarmBitsArray[13]);
        currentData.setTemp3AlarmBit((int) alarmBitsArray[12]);
        currentData.setTemp4AlarmBit((int) alarmBitsArray[11]);
        currentData.setDi1AlarmBit((int) alarmBitsArray[7]);
        currentData.setDi2AlarmBit((int) alarmBitsArray[6]);
        currentData.setLeakageFaultBit((int) faultBitsArray[15]);
        currentData.setTemp1FaultBit((int) faultBitsArray[14]);
        currentData.setTemp2FaultBit((int) faultBitsArray[13]);
        currentData.setTemp3FaultBit((int) faultBitsArray[12]);
        currentData.setTemp4FaultBit((int) faultBitsArray[11]);
        currentData.setLeakageLinkBit((int) linkBitsArray[15]);
        currentData.setTemp1LinkBit((int) linkBitsArray[14]);
        currentData.setTemp2LinkBit((int) linkBitsArray[13]);
        currentData.setTemp3LinkBit((int) linkBitsArray[12]);
        currentData.setTemp4LinkBit((int) linkBitsArray[11]);
        currentData.setDi1LinkBit((int) linkBitsArray[7]);
        currentData.setDi2LinkBit((int) linkBitsArray[6]);
        currentData.setDo1LinkBit((int) linkBitsArray[5]);   // 位10 -> 索引5
        currentData.setDo2LinkBit((int) linkBitsArray[4]);   // 位11 -> 索引4
        currentData.setOvervoltage((int) limitBitsArray[15]);
        currentData.setUndervoltage((int) limitBitsArray[14]);
        currentData.setPhaseloss((int) limitBitsArray[13]);
        currentData.setOvercurrent((int) limitBitsArray[12]);
        currentData.setOvercapacity((int) limitBitsArray[11]);
        currentData.setLeakageValue((double) actualLeakage);
        currentData.setTemp1((double) actualTemps[0]);
        currentData.setTemp2((double) actualTemps[1]);
        currentData.setTemp3((double) actualTemps[2]);
        currentData.setTemp4((double) actualTemps[3]);
        currentData.setPtRatio(actualPtRatio);
        currentData.setCtRatio(actualCtRatio);
        // 设置通道数量
        currentData.setLeakageChannels(Integer.parseInt(leakageChannels, 16));
        currentData.setTempChannels(Integer.parseInt(tempChannels, 16));
        // 设置DI报警状态
        currentData.setDi1AlarmBit((int) alarmBitsArray[7]);  // 对应位8(DI1联动)
        currentData.setDi2AlarmBit((int) alarmBitsArray[6]);  // 对应位9(DI2联动)
        // 设置电压电流值
        currentData.setVoltageA((double) actualVoltage1);
        currentData.setVoltageB((double) actualVoltage2);
        currentData.setVoltageC((double) actualVoltage3);
        currentData.setCurrentA((double) actualCurrent1);
        currentData.setCurrentB((double) actualCurrent2);
        currentData.setCurrentC((double) actualCurrent3);
        // 设置功率和电能
        currentData.setPower((double) actualPower);
        currentData.setEnergy(actualEnergy);
        // 设置控制码信息
        currentData.setCtrlDataDomain(bit7_6);       // 数据域类型
        currentData.setCtrlNeedAck(bit5);            // 应答标识
        currentData.setCtrlCommStatus(bit4);         // 通信状态
        currentData.setCtrlReportMode(bit3_2);       // 上报模式
        currentData.setCtrlAddrMode(bit1_0);         // 寻址模式

        // 保存或更新实时数据
        LambdaQueryWrapper<Sdf300CurrentData> currentQuery = new LambdaQueryWrapper<>();
        currentQuery.eq(Sdf300CurrentData::getEquipmentInputStoreId, equipmentInputStoreId);
        sdf300CurrentDataService.saveOrUpdate(currentData);
        // 保存历史数据
        Sdf300HistoryData historyData = new Sdf300HistoryData();
        BeanUtil.copyProperties(currentData, historyData, true);
        sdf300HistoryDataService.save(historyData);

        // 保存报警数据
        if (!equipmentInputStore.getState().equals("0")) {
            Sdf300WarnData sdf300WarnData = new Sdf300WarnData();
            BeanUtil.copyProperties(currentData, sdf300WarnData, true);
            sdf300WarnDataService.save(sdf300WarnData);
            WarnRecord warnRecord = new WarnRecord();
            warnRecord.setEquipmentInputStoreId(equipmentInputStore.getId());
            warnRecord.setWarnStateNum(equipmentInputStore.getState());
            warnRecord.setWarnTypeNum(0);
            warnRecord.setIsDeal(0);
            warnRecord.setIsMisinformation("0");
            warnRecord.setTeleNotification("1");
            warnRecord.setFaultReport("0");
            warnRecord.setFieldSurvey("0");
            warnRecord.setEliminHidDang("0");
            warnRecord.setCreateTime(LocalDateTime.now());
            warnRecord.setWarnTime(sendTime);
            warnRecord.setWarnAddr(equipmentInputStore.getAddress());
            warnRecord.setIsDelete(0);
            warnRecordService.save(warnRecord);
            //报警推送
            ArrayList<WarnRecord> warnRecords = new ArrayList<>();
            warnRecords.add(warnRecord);
            sendWarnNotice(equipmentInputStore, warnRecords);
        }

        //记录设备数据上传内容
        saveFireSysData(deviceId, "上传SDF300设备数据包", sendTime);
        //更新设备数据上传时间(用于记录设备是否在线)
        updateTemporaryData(deviceId, sendTime);
        log.info("SDF300设备数据包保存成功: {}", deviceId);
    }
}
